using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Calculations.Calculations;

namespace Atechnology.glassCAD.Shapes.CutViewer
{
    public class Arc : IGeometry, IComparable<Arc>
    {
        private double tag;
        internal double Tag
        {
            get { return tag; }
            set { tag = value; }
        }

        private bool drawRadius = false;

        public bool DrawRadius
        {
            get { return drawRadius; }
            set { drawRadius = value; }
        }

        private bool drawBoundingBox = false;

        public bool DrawBoundingBox
        {
            get { return drawBoundingBox; }
            set { drawBoundingBox = value; }
        }

        private Tip tip;

        public Tip Tip
        {
            get { return tip; }
        }

        private PointF center;

        public PointF Center
        {
            get { return center; }
            set { center = value; }
        }
        private float radius;

        public float Radius
        {
            get { return radius; }
            set { radius = value; }
        }
        private float startAngle;

        public float StartAngle
        {
            get { return startAngle; }
            set { startAngle = value; }
        }
        private float endAngle;

        public float EndAngle
        {
            get { return endAngle; }
            set { endAngle = value; }
        }

        public float Angle
        {
            get
            {
                if (this.endAngle < this.startAngle)
                    return (float)(2 * Math.PI - (this.startAngle - this.endAngle));
                else
                    return this.endAngle - this.startAngle;
            }
        }

        private PointF startPoint;

        public PointF StartPoint
        {
            get 
            {
                startPoint.X = (float)(center.X + radius * Math.Cos(startAngle));
                startPoint.Y = (float)(center.Y + radius * Math.Sin(startAngle));
 
                return startPoint; 
            }
        }

        private PointF endPoint;

        public PointF EndPoint
        {
            get 
            {
                endPoint.X = (float)(center.X + radius * Math.Cos(endAngle));
                endPoint.Y = (float)(center.Y + radius * Math.Sin(endAngle));
                return endPoint; 
            }
        }

        public Arc()
        {
            center = new PointF();
            startPoint = new PointF();
            endPoint = new PointF();
            this.tip = new Tip();
        }

        public Arc(PointF startPoint, PointF endPoint, float radius)
        {
            this.startPoint = startPoint;
            this.endPoint = endPoint;
            this.radius = radius;            
            this.tip = new Tip();
            this.RecalculateParameters(startPoint, endPoint, radius);
        }

        public PointF GetPoint(double offset)
        {           
            PointF point = GeometryCalculations.RotatePoint(this.startPoint, this.center, this.Angle * offset);
            return point;
        }

        private void RecalculateParameters(PointF startPoint, PointF endPoint, float radius)
        {
            PointF middlePoint = new PointF((startPoint.X + endPoint.X) / 2, (startPoint.Y + endPoint.Y) / 2);
            Calculations.Vector normalLine = GeometryCalculations.GetNormalLine(startPoint, endPoint, 0.5);
            
            double H = GeometryCalculations.GetDistance(startPoint, endPoint) / 2;
            double offset = Math.Sqrt(radius * radius - H * H);
            normalLine.Length = offset;
            this.center = GeometryCalculations.GetOffsetPoint(middlePoint, normalLine);
            this.startAngle = (float)GeometryCalculations.GetAngle(this.center, new PointF(this.center.X + 1, this.center.Y), startPoint);
            this.endAngle = (float)GeometryCalculations.GetAngle(this.center, new PointF(this.center.X + 1, this.center.Y), endPoint);
        }

        #region IFigure Members

        public void Draw(System.Drawing.Graphics g, RectangleF modelBoundingBox, int screenWidth, int screenHeight, IDrawVisitor drawVisitor)
        {
            try
            {
                drawVisitor.Visit(this, g, modelBoundingBox, screenWidth, screenHeight);
            }
            catch
            {
            }
            //PointF start = new PointF();
            //PointF end = new PointF();

            //start.X = center.X - radius;
            //start.Y = center.Y + radius;

            //end.X = center.X + radius;
            //end.Y = center.Y - radius;
            
            //start = CoordinateConverter.ModelToScreen(start, modelBoundingBox, screenWidth, screenHeight);
            //end = CoordinateConverter.ModelToScreen(end, modelBoundingBox, screenWidth, screenHeight);
            //float r = CoordinateConverter.ModelToScreen(radius, modelBoundingBox, screenWidth, screenHeight);

            //RectangleF arcRect = new RectangleF(start.X, start.Y, 2 * r, 2 * r);

            //float startAngleInDegrees = 360 - (float)(endAngle * 180 / Math.PI);
            //float endAngleInDegrees = 360 - (float)(startAngle * 180 / Math.PI);

            //float sweepAngleInDegrees;
            //if (endAngleInDegrees < startAngleInDegrees)
            //    endAngleInDegrees += 360;
            //sweepAngleInDegrees = endAngleInDegrees - startAngleInDegrees;

            //g.DrawArc(pen, arcRect, startAngleInDegrees, sweepAngleInDegrees);
            //if(tip.Enabled)
            //    tip.Draw(g, modelBoundingBox, screenWidth, screenHeight, Pens.Blue);

            //if (this.drawBoundingBox)
            //{
            //    RectangleF bbox = BoundingBox;
            //    PointF scrStartPoint = CoordinateConverter.ModelToScreen(StartPoint, modelBoundingBox, screenWidth, screenHeight);
            //    PointF scrEndPoint = CoordinateConverter.ModelToScreen(EndPoint, modelBoundingBox, screenWidth, screenHeight);

            //    double scrWidth = CoordinateConverter.ModelToScreen(bbox.Size.Width, modelBoundingBox, screenWidth, screenHeight);
            //    double scrHeight = CoordinateConverter.ModelToScreen(bbox.Size.Height, modelBoundingBox, screenWidth, screenHeight);
            //    PointF location = CoordinateConverter.ModelToScreen(bbox.Location, modelBoundingBox, screenWidth, screenHeight);
           
            //    location.Y = (float)(location.Y - scrHeight);

            //    Color color = Color.FromArgb(35, 200, 230, 190);
            //    Brush brush = new SolidBrush(color);
            //    g.FillRectangle(brush, location.X, location.Y, (float)scrWidth, (float)scrHeight);
            //    g.DrawRectangle(Pens.Gray, location.X, location.Y, (float)scrWidth, (float)scrHeight);
            //    g.FillEllipse(Brushes.Green, scrStartPoint.X - 4, scrStartPoint.Y - 4, 8, 8);
            //    g.FillEllipse(Brushes.Green, scrEndPoint.X - 4, scrEndPoint.Y - 4, 8, 8);
            //    brush.Dispose();
            //}
        }

        public System.Drawing.RectangleF BoundingBox
        {
            get 
            {
                RectangleF bbox = new RectangleF();
                PointF start = this.StartPoint;
                PointF end = this.EndPoint;
                //int startAngleSector;
                //int endAngleSector;

//                double sweepAngle;
                if (Math.Abs(startAngle - 2 * Math.PI) < 0.0001) startAngle = 0;

                //if (startAngle > endAngle)
                //    sweepAngle = 2 * Math.PI - (startAngle - endAngle);
                //else
                //    sweepAngle = endAngle - startAngle;

                //startAngleSector = Utils.GetAngleSector(startAngle);
                //endAngleSector = Utils.GetAngleSector(endAngle);

                if (Utils.IsAngleInRange(Math.PI / 2, startAngle, endAngle))
                {
                    bbox.Height += radius;
                }
                else
                {
                    bbox.Height += Math.Max(start.Y - center.Y, end.Y - center.Y);
                }

                if (Utils.IsAngleInRange(Math.PI, startAngle, endAngle))
                {
                    bbox.Width += radius;
                    bbox.X = center.X - radius;
                }
                else
                {
                    bbox.Width += center.X - Math.Min(start.X, end.X);
                    bbox.X = Math.Min(start.X, end.X);
                }
                if (Utils.IsAngleInRange(3 * Math.PI / 2, startAngle, endAngle))
                {
                    bbox.Height += radius;
                    bbox.Y = center.Y - radius;
                }
                else
                {
                    bbox.Height += center.Y - Math.Min(start.Y, end.Y);
                    bbox.Y = Math.Min(start.Y, end.Y);
                }

                if (Utils.IsAngleInRange(0, startAngle, endAngle))
                {
                    bbox.Width += radius;
                }
                else
                {
                    bbox.Width += Math.Max(start.X - center.X, end.X - center.X);
                }
                return bbox;
            }
        }

        #endregion

        #region IGeometry Members


        public void Update()
        {
            tip.Location = new PointF(center.X, center.Y);
        }

        #endregion

        #region IComparable<Arc> Members

        public int CompareTo(Arc other)
        {
            if (this.tag < other.tag)
                return -1;
            else if (GeometryCalculations.IsEqual(this.tag, other.tag, 0.00001))
                return 0;
            else
                return 1;
        }

        #endregion
    }
}
